﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace RQX.Common.Core.Hardware.Net
{
    public class TcpSocketConnection
    {
        private readonly Socket _socket;
        private readonly TcpSocketServer _server;
        private DateTime _lastCommunicationTime;
        /// <summary>
        /// 缓冲区最大容积
        /// </summary>
        private const int ContainerLength = 524288;
        /// <summary>
        /// 需要进行连接检查的时间
        /// </summary>
        private const int NeedCheckConnectedTime = 10000;
        public TcpSocketConnection(TcpSocketServer server, Socket socket)
        {
            _server = server;
            _socket = socket;
            Recv();
        }
        #region 对外接口
        /// <summary>
        /// 获取当前连接数
        /// </summary>
        /// <returns></returns>
        public int GetSocketNum() => _server._socketList.Count;
        /// <summary>
        /// 判断是否还在连接中，如果未连接，则关闭当前连接
        /// </summary>
        /// <returns></returns>
        public bool CheckIsConnected()
        {
            if (_lastCommunicationTime.AddMilliseconds(NeedCheckConnectedTime) < DateTime.Now)
            {
                if (!IsConnected())
                {
                    Close();
                    return false;
                }
            }
            return true;
        }

        private bool IsConnected()
        {
            bool part1 = _socket.Poll(1000, SelectMode.SelectRead | SelectMode.SelectWrite);
            bool part2 = (_socket.Available == 0);
            if (part1 && part2)
                return false;
            else
                return true;
        }
        public void Send(byte[] buffer)
        {
            TryCatchMethod(() =>
            {
                _socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, asyncResult =>
                {
                    TryCatchMethod(() =>
                    {
                        _socket.EndSend(asyncResult);
                        _lastCommunicationTime = DateTime.Now;
                        HandleMsgSended?.Invoke(this, buffer);
                    });
                }, null);
            });
        }

        public void Recv()
        {
            byte[] container = new byte[ContainerLength];
            TryCatchMethod(() =>
            {
                _socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
                {
                    TryCatchMethod(() =>
                    {
                        var length = _socket.EndReceive(asyncResult);
                        if (length > 0)
                        {
                            if (IsConnected()) Recv();
                            _lastCommunicationTime = DateTime.Now;
                            byte[] buffer = new byte[length];
                            Array.Copy(container, 0, buffer, 0, length);
                            HandleMsgReceived?.Invoke(this, buffer);
                            container = null;
                            buffer = null;
                        }
                    });
                }, null);
            });
        }

        public void Close()
        {
            _server._socketList.TryRemove(_socket.RemoteEndPoint, out var conn);
            _socket.Close();
            HandleClosed?.Invoke(this);
        }
        #endregion

        #region 内部函数
        private void TryCatchMethod(Action action)
        {
            try
            {
                action();
            }
            catch (Exception ex)
            {
                Close();
                HandleException?.Invoke(this, ex);
            }
        }
        #endregion

        #region 处理事件
        /// <summary>
        /// 接收到数据触发的事件
        /// </summary>
        public Action<TcpSocketConnection, byte[]> HandleMsgReceived { get; set; }
        /// <summary>
        /// 发送数据后触发的事件
        /// </summary>
        public Action<TcpSocketConnection, byte[]> HandleMsgSended { get; set; }
        /// <summary>
        /// 连接关闭事件
        /// </summary>
        public Action<TcpSocketConnection> HandleClosed { get; set; }
        /// <summary>
        /// 异常处理事件
        /// </summary>
        public Action<TcpSocketConnection, Exception> HandleException { get; set; }
        #endregion
    }
}
